home *** CD-ROM | disk | FTP | other *** search
Java Source | 1997-07-18 | 11.7 KB | 456 lines |
- /*
- * @(#)HttpServer.java 1.20 97/06/16
- *
- * Copyright (c) 1995-1997 Sun Microsystems, Inc. All Rights Reserved.
- *
- * This software is the confidential and proprietary information of Sun
- * Microsystems, Inc. ("Confidential Information"). You shall not
- * disclose such Confidential Information and shall use it only in
- * accordance with the terms of the license agreement you entered into
- * with Sun.
- *
- * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
- * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
- * PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES
- * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
- * THIS SOFTWARE OR ITS DERIVATIVES.
- *
- * CopyrightVersion 1.0
- */
-
- package sun.servlet.http;
-
- import sun.servlet.*;
- import sun.servlet.util.*;
- import javax.servlet.*;
- import java.net.*;
- import java.io.*;
- import java.util.Enumeration;
- import java.util.Properties;
-
- /**
- * This class implements a simple HTTP server for testing servlets.
- *
- * @version 1.20, 06/16/97
- * @author David Connelly
- */
- public
- class HttpServer implements Runnable, ServletContext {
- /**
- * The queue of pending connections.
- */
- protected Queue connections;
-
- /**
- * The thread group for connection handlers.
- */
- protected ThreadGroup handlers;
-
- /**
- * The maximum number of handler threads.
- */
- protected int maxHandlers = 100;
-
- /**
- * The handler timeout in milliseconds.
- */
- protected int timeout = 5000;
-
- /**
- * The server port number.
- */
- protected int port = 8080;
-
- /**
- * The backlog parameter to use when creating the server socket.
- */
- protected int backlog = 50;
-
- /**
- * The number of available handlers.
- */
- protected int avail;
-
- /**
- * The total number of active handlers.
- */
- protected int total;
-
- /**
- * The name of the server.
- */
- protected String name = "ServletServer/1.0";
-
- /**
- * The host name of the server.
- */
- protected String host;
-
- /**
- * The directory where servlets are stored.
- */
- protected String servletDir = ".";
-
- /**
- * The properties list that decribes servlet aliases and init args
- */
- protected Properties servletProps = new Properties();
-
- /**
- * The filename which contains servlet properties
- */
- protected String servletPropFile =
- servletDir+System.getProperty("file.separator")+"servlets.properties";
-
- /**
- * The document root directory for serving files.
- */
- protected String documentDir = ".";
-
- /**
- * The servlet loader.
- */
- protected ServletLoader loader;
-
- /**
- * Set to true for verbose output.
- */
- protected boolean verbose;
-
- /**
- * Creates a new HTTP server with default parameters.
- */
- public HttpServer() {
- }
-
- /**
- * Creates a new HTTP server with parameters from the specified properties.
- * @param props the server properties
- */
- public HttpServer(Properties props) {
- loadProperties(props);
- }
-
- /**
- * Load servlet properties from servlet prop file
- */
- private void loadServletProps() {
- File spf = new File(servletPropFile);
- if (spf.exists() && spf.canRead()) {
- try {
- servletProps.load(new FileInputStream(spf));
- } catch (IOException ioe) {
- System.err.println("Could not load servlet properites file");
- ioe.printStackTrace(System.err);
- }
-
- }
- }
-
- /**
- * Loads parameters from the specified properties.
- * @param props the server properties
- */
- public void loadProperties(Properties props) {
- host = getHostName();
- port = getIntProperty(props, "server.port", port);
- backlog = getIntProperty(props, "server.backlog", backlog);
- maxHandlers = getIntProperty(props, "server.max.handlers", maxHandlers);
- timeout = getIntProperty(props, "server.timeout", timeout);
- name = props.getProperty("server.name", name);
- servletDir = props.getProperty("servlet.dir", servletDir);
- documentDir = props.getProperty("document.dir", documentDir);
- servletPropFile = props.getProperty("servlet.propfile",
- servletPropFile);
- loadServletProps();
- }
-
- /**
- * Returns the integer value of a property.
- */
- protected static int getIntProperty(Properties prop, String name, int def) {
- String s = prop.getProperty(name);
- try {
- return s != null ? Integer.parseInt(s) : def;
- } catch (NumberFormatException e) {
- return def;
- }
- }
-
- /**
- * Returns the host name of the server.
- */
- protected static String getHostName() {
- InetAddress addr;
- try {
- addr = InetAddress.getLocalHost();
- } catch (UnknownHostException e) {
- return null;
- }
- String host = addr.getHostName();
- if (host == null || host.indexOf('.') == -1) {
- // If host does not appear to be fully qualified, then return
- // just the inet address instead.
- host = addr.getHostAddress();
- }
- return host;
- }
-
- /**
- * Runs the servlet server.
- */
- public void run() {
- if (verbose) {
- printSettings();
- }
- // initialize connection handlers
- connections = new Queue(maxHandlers);
- handlers = new ThreadGroup("ServletServer-");
- // create servlet loader
- loader = new ServletLoader(servletDir);
- // create server socket for accepting new connections
- ServerSocket ss;
- try {
- ss = new ServerSocket(port, backlog);
- } catch (IOException e) {
- e.printStackTrace();
- return;
- }
- // accept and dispatch connections
- while (true) {
- // first wait for an available handler thread
- synchronized (this) {
- while (avail <= 0) {
- // fork a new handler if none are currently available
- if (total < maxHandlers) {
- Runnable handler = new HttpServerHandler(this);
- new Thread(handlers, handler).start();
- total++;
- }
- // wait for handler to become ready
- try {
- wait();
- } catch (InterruptedException e) {
- }
- }
- --avail;
- }
- // got handler, now accept new connection and add to queue
- Socket s = null;
- try {
- s = ss.accept();
- putConnection(s);
- } catch (IOException e) {
- e.printStackTrace();
- if (s != null) {
- try {
- s.close();
- } catch (IOException ee) {
- }
- }
- }
- }
- }
-
- /**
- * Places the specified connection object on the queue of pending
- * connections.
- */
- protected void putConnection(Object s) {
- try {
- synchronized (connections) {
- connections.add(s);
- connections.notify();
- }
- } catch (QueueFullException e) {
- throw new InternalError("connection queue overflow");
- }
- }
-
- /**
- * Called by a connection handler to retrieve the next connection from
- * the queue. If this method returns null then the handler should
- * exit as the thread has expired.
- */
- public Object getConnection() {
- // indicate that we are ready for a new connection
- long timeout;
- synchronized (this) {
- timeout = this.timeout;
- avail++;
- notify();
- }
- // wait for next connection
- while (true) {
- long initial = System.currentTimeMillis();
- long elapsed = 0;
- synchronized (connections) {
- while (connections.empty() && elapsed < timeout) {
- try {
- connections.wait(timeout - elapsed);
- } catch (InterruptedException e) {
- }
- elapsed = System.currentTimeMillis() - initial;
- }
- try {
- return connections.remove();
- } catch (QueueEmptyException e) {
- // timed out while waiting for connection
- }
- }
- // timed out so return null to indicate that the handler
- // should exit
- --total;
- --avail;
- return null;
- }
- }
-
- /**
- * Gets a servlet by name.
- */
- public Servlet getServlet(String name) {
- // First attempt to resolve the name against the prop file
- String cname = servletProps.getProperty("servlet."+name+".code");
- String init = servletProps.getProperty("servlet."+name+".initArgs");
- try {
- if (cname == null) {
- return loader.loadServlet(name,
- new HttpServletConfig( this,
- init));
- } else {
- return loader.loadServlet(cname,
- new HttpServletConfig( this,
- init));
- }
- } catch (ServletException e) {
- e.printStackTrace();
- return null;
- }
- }
-
- /**
- * Enumerates the servlets in this server.
- */
- public Enumeration getServlets() {
- return loader.getServlets();
- }
-
- /**
- * Writes a message to the servlet log.
- */
- public void log(String msg) {
- System.err.println(msg);
- }
-
- /**
- * Returns the mime type of the specified file.
- */
- public String getMimeType(String name) {
- return HackURLConnection.guessContentTypeFromName(name);
- }
-
- /**
- * Returns the translated path for the specified virtual path.
- */
- public String getRealPath(String path) {
- path = documentDir + path;
- return path.replace('/', File.separatorChar);
- }
-
- /**
- * Returns the name and version of the current server.
- */
- public String getServerInfo() {
- return name;
- }
-
- /**
- * Returns an attribute of the server for the specified key name.
- * @param name the attribute name
- * @return the value of the attribute or null if not found
- */
- public Object getAttribute(String name) {
- return null;
- }
-
- /**
- * Runs the HTTP server.
- */
- public static void main(String args[]) {
- HttpServer server = new HttpServer();
- Properties props = new Properties();
- try {
- for (int i = 0; i < args.length; i++) {
- String arg = args[i];
- if ("-p".equals(arg)) {
- props.put("server.port", args[++i]);
- } else if ("-b".equals(arg)) {
- props.put("server.backlog", args[++i]);
- } else if ("-m".equals(arg)) {
- props.put("server.max.handlers", args[++i]);
- } else if ("-t".equals(arg)) {
- props.put("server.timeout", args[++i]);
- } else if ("-d".equals(arg)) {
- props.put("servlet.dir", args[++i]);
- } else if ("-r".equals(arg)) {
- props.put("document.dir", args[++i]);
- } else if ("-s".equals(arg)) {
- props.put("servlet.propfile", args[++i]);
- } else if ("-v".equals(arg)) {
- server.verbose = true;
- } else {
- server.help();
- }
- }
- server.loadProperties(props);
- } catch (ArrayIndexOutOfBoundsException e) {
- server.help();
- }
- server.run();
- }
-
- protected void printSettings() {
- PrintStream err = System.err;
- err.println("Server settings:");
- err.println(" port = " + port);
- err.println(" backlog = " + backlog);
- err.println(" max handlers = " + maxHandlers);
- err.println(" timeout = " + timeout);
- err.println(" servlet dir = " + servletDir);
- err.println(" document dir = " + documentDir);
- err.println(" servlet propfile = " + servletPropFile);
- }
-
- protected static void help() {
- PrintStream err = System.err;
- err.println("Usage: srun [options]");
- err.println("Options:");
- err.println(" -p port the port number to listen on");
- err.println(" -b backlog the listen backlog");
- err.println(" -m max maximum number of connection handlers");
- err.println(" -t timeout connection timeout in milliseconds");
- err.println(" -d dir servlet directory");
- err.println(" -r root document root directory");
- err.println(" -s filename servlet property file name");
- err.println(" -v verbose output");
- System.exit(1);
- }
-
- }
-
- /*
- * This class is used to extend java.net.URLConnection so that we can
- * access the method guessContentTypeFromName(). For some reason, that
- * method is protected even though guessContentTypeFromStream is public.
- */
- abstract class HackURLConnection extends URLConnection {
- protected HackURLConnection(URL url) {
- super(url);
- }
- public static String guessContentTypeFromName(String fname) {
- return URLConnection.guessContentTypeFromName(fname);
- }
- }
-